//------------------------------------------------------------------------------
// <copyright file="AsyncResult.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>
// Implementation of AsyncResult with a return value of type TResult
// Taken from Jeffrey Richter's Concurrent Affairs MSDN Library article
// with only stylistic changes
// </summary>
//------------------------------------------------------------------------------

namespace Microsoft.Internal.GamesTest.Rpc.Client
{
    using System;

    /// <summary>
    /// Implementation of IAsyncResult with a return value of type TResult.
    /// </summary>
    /// <typeparam name="TResult">The type of the result associated with this AsyncResult.</typeparam>
    internal class AsyncResult<TResult> : AsyncResultNoResult
    {
        // Field set when operation completes
        private TResult internalResult = default(TResult);
        
        /// <summary>
        /// Initializes a new instance of the AsyncResult class.
        /// </summary>
        public AsyncResult()
            : base()
        {
        }

        /// <summary>
        /// Gets the internal result.
        /// </summary>
        /// <value>The result.</value>
        public TResult Result 
        { 
            get 
            { 
                return this.internalResult; 
            } 
        }

        /// <summary>
        /// Tells the AsyncResult that the operation is completed.
        /// </summary>
        /// <param name="result">The result to set.</param>
        /// <param name="completedSynchronously">Whether or not the result compeleted Synchronously or Asynchronously.</param>
        /// <param name="exception">The exception thrown by the target, or null if no exception.</param>
        public void SetAsCompleted(TResult result, bool completedSynchronously, Exception exception = null)
        {
            // Save the asynchronous operation's result
            this.internalResult = result;

            // Tell the base class that the operation completed with an exception.
            base.SetAsCompleted(exception, completedSynchronously);
        }

        /// <summary>
        /// Waits until the async operation is complete and gets the result.
        /// </summary>
        /// <param name="timeout">The amount of time to wait for the async operation to complete.</param>
        /// <returns>The result of the operation.</returns>
        public new TResult EndInvoke(TimeSpan timeout)
        {
            base.EndInvoke(timeout); // Wait until operation has completed 
            return this.internalResult;  // Return the result (if above didn't throw)
        }
    }
}